package org.gitos.cloud.server.rpc;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;

import org.gitos.cloud.domain.rpc.LoginRPC;
import org.gitos.cloud.domain.server.User;
import org.gitos.cloud.server.service.UserService;
import org.gitos.cloud.util.AuthCodeKit;
import org.gitos.cloud.util.CommonKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * Created by shizhengchu on 16/1/18.
 */
@Service(timeout = 5000)
public class LoginRPCImp extends CommonMethod implements LoginRPC {

    private static Logger log = LoggerFactory.getLogger(LoginRPCImp.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    @Value("${sms.api}")
    private String smsApi;
    @Value("${sms.expire_time}")
    private Long expire_time;

    // 轻码云短信
    @Value("${lt_sms.accountSid}")
    private String accountSid;
    @Value("${lt_sms.appId}")
    private String appId;
    @Value("${lt_sms.templateId}")
    private String lt_templateId;
    @Value("${lt_sms.authToken}")
    private String authToken;

    // 阿里百川短信
    @Value("${ali_sms.appKey}")
    private String appKey;
    @Value("${ali_sms.secret}")
    private String secret;
    @Value("${ali_sms.signId}")
    private Long signId;
    @Value("${ali_sms.templateId}")
    private Long templateId;
    @Value("${ali_sms.code_key}")
    private String code_key;
    @Value("${ali_sms.expire_time_key}")
    private String expire_time_key;

    /* 登录验证码有效时间 */
    private static final int AUTHCODE_LOGIN_EXPIRE_TIME = 15;
    /* 登录验证码在session中的key前缀 */
    private static final String AUTHCODE_LOGIN_PREFIX = "ac_login";
    /* 注册验证码在session中的key前缀 */
    private static final String AUTHCODE_REGISTER_PREFIX = "ac_register";
    /* 登录错误次数 */
    private static final String ERROR_COUNT_SUFFIX = "error_count";

    @Override
    public HashMap<String, Object> register(JSONObject jo) {
        String username = jo.getString("username");
        String authCode = jo.getString("authCode");
        if (authCode == null || "".equals(authCode)) {
            return fail("验证码不能为空");
        }
        String authCode_ = redisTemplate.opsForValue()
                .get(AUTHCODE_REGISTER_PREFIX + username);
        if (authCode_ == null) {
            return fail("验证码已失效");
        }
        if (!authCode.equals(authCode_)) {
            return fail("验证码不正确");
        }
        Object o = userService.saveLocalUser(username, jo.getString("password"),
                jo.getString("nickname"), jo.getBytes("headimg"),
                jo.getIntValue("gender"));
        if (o instanceof User) {
            User user=(User)o;
            redisTemplate.opsForValue().set(user.getUuid(),JSONObject.toJSONString(user),36,TimeUnit.DAYS);
            return success(o);
        }
        return fail(o);
    }

    @Override
    public HashMap<String, Object> isUserExist(String token) {
        return success(userService.getUserByToken(token) != null);
    }

    @Override
    public HashMap<String, Object> sendAuthCode(String mobile) {
        String acKey = AUTHCODE_REGISTER_PREFIX + mobile;
        if ("lt".equals(smsApi)) {
            return throughLightCodeCloud(mobile);
        } else {
            return throughAliBaiChuan(mobile);
        }
    }

    /**
     * 轻码云通讯
     */
    private HashMap<String, Object> throughLightCodeCloud(String mobile) {
        String authCode = AuthCodeKit.generateAuthCodeOfNum(6);
        HttpURLConnection con = null;
        URL url;
        try {
            HashMap<String, String> paras = new HashMap<String, String>();
            paras.put("accountSid", accountSid);
            paras.put("appId", appId);
            paras.put("templateId", lt_templateId);
            paras.put("to", mobile);
            paras.put("param", authCode + "," + expire_time);
            SimpleDateFormat sd = new SimpleDateFormat("yyyyMMddHHmmss");
            String timestamp = sd.format(new Date());
            paras.put("timestamp", timestamp);
            String sig = CommonKit.md5(accountSid + authToken + timestamp).toLowerCase();
            paras.put("sig", sig);
            url = new URL("https://api.qingmayun.com/20150822/SMS/templateSMS?" + CommonKit.encodePara(paras));
            con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-type",
                    "application/x-www-form-urlencoded;charset=utf-8");
            con.setConnectTimeout(20000);
            con.setDefaultUseCaches(false);
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    con.getInputStream()));
            String line = null;
            String returnjson = "";
            while ((line = in.readLine()) != null) {
                returnjson += line;
            }
            JSONObject out = JSONObject.parseObject(returnjson);
            if ("00000".equals(out.getString("respCode"))) {
                redisTemplate.opsForValue().set(
                        AUTHCODE_REGISTER_PREFIX + mobile, authCode,
                        expire_time, TimeUnit.MINUTES);
                return success(null);
            }
        } catch (Exception e) {
        }
        return fail("发送验证码失败");
    }

    /**
     * 阿里百川
     */
    private HashMap<String, Object> throughAliBaiChuan(String mobile) {
        return fail("验证码发送失败");
    }

    @Override
    public HashMap<String, Object> login(String username, String password, String authCode) {
        String isNeedAuth = redisTemplate.opsForValue().get(
                username + ERROR_COUNT_SUFFIX);
        int errCount = 0;
        if (isNeedAuth != null) {
            errCount = Integer.parseInt(isNeedAuth);
            if (errCount >= 3) {
                String authCode_old = redisTemplate.opsForValue().get(
                        AUTHCODE_LOGIN_PREFIX + username);
                if (authCode_old == null) {
                    return fail("验证码已失效");
                } else if (!authCode_old.equals(authCode)) {
                    return fail("验证码错误");
                } else {
                    redisTemplate.opsForValue().set(
                            username + ERROR_COUNT_SUFFIX, "0");
                }
            }
        }
        User user = userService.login(username, password);
        // 登录成功
        if (user != null) {
            redisTemplate.delete(username + ERROR_COUNT_SUFFIX);
            redisTemplate.opsForValue().set(user.getUuid(), JSONObject.toJSONString(user), 36, TimeUnit.DAYS);
        } else {
            redisTemplate.opsForValue().set(username + ERROR_COUNT_SUFFIX,
                    ++errCount + "", 2, TimeUnit.HOURS);
            return fail("用户名或密码错误");
        }
        return success(user);
    }

    @Override
    public byte[] generateAuthCode(String username) {
        String authCode = AuthCodeKit.generateAuthCode(4);
        BufferedImage authCodeImage = AuthCodeKit
                .generateAuthCodeImage(authCode);
        // 将认证码存入redis
        String acKey = AUTHCODE_LOGIN_PREFIX + username;
        redisTemplate.opsForValue().set(acKey, authCode);
        redisTemplate.expire(acKey, AUTHCODE_LOGIN_EXPIRE_TIME,
                TimeUnit.MINUTES);
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        // 输出图象到页面
        try {
            ImageIO.write(authCodeImage, "JPEG", bs);
        } catch (IOException e) {
            return null;
        }
        return bs.toByteArray();
    }

    @Override
    public HashMap<String, Object> thirdPartyUserLogin(JSONObject user) {
        String openid = user.getString("openid");
        // 用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。若用户更换头像，原有头像URL将失效。
        Object o = userService.saveThirdPartyUser(openid,
                user.getString("nickname"), user.getBytes("headimg"),
                user.getIntValue("sex"), user.getString("from"));
        if (o instanceof User) {
            User user_=(User)o;
            redisTemplate.opsForValue().set(user_.getUuid(), JSONObject.toJSONString(user_), 36, TimeUnit.DAYS);
        }
        return success(o);
    }

    @Override
    public HashMap<String, Object> loginOut(String uuid) {
        if (uuid == null) {
            return fail("用户未登录");
        }
        redisTemplate.delete(uuid);
        return success(null);
    }

    @Override
    public HashMap<String, Object> checkLoginState(String user_uuid) {
        String user = redisTemplate.opsForValue().get(user_uuid);
        return success(user != null && !"".equals(user));
    }

    @Override
    public HashMap<String, Object> updateUser(User userStr) {
        return judge(userService.updateUser(userStr));
    }
}
